#include <cstdlib>
#include <iostream>
#include <vector>
#include <queue>
#include <string>
#include "server_thread_aceptar.h"
#include "server_thread_cliente.h"
#include "server_thread_crear_partida.h"
#include "server_socket.h"
#include "server_Partida.h"
#include "common_ParserXML.h"
#include "server_Configuracion.h"
#include "common_LectorDirectorio.h"
#include "common_Mutex.h"
#define PORT 4321
#define RUTA "campaigns/"
#define LARGO 5

using std::cout;
using std::stoi;
using std::stof;
using std::endl;
using std::string;
using std::vector;
using std::queue;

Server_thread_aceptar::Server_thread_aceptar(Server_socket* s, bool* correr) {
    socket = s;
    correServer = correr;
    indiceCliente = 0;
}

Server_thread_aceptar::~Server_thread_aceptar() {
}

/* Ejecutar: funcion donde hay un bucle para aceptar conexiones. */
void Server_thread_aceptar::ejecutar() {
    configurarDatosDePartidas();
    Mutex mutex;
    vector<Partida*> *listaPartidas = new vector<Partida*>;
    vector<Partida*> *listaDePartidasPendientes = new vector<Partida*>;

    ParserXML parser;
    LectorDirectorio lector;
    vector<string> archivos = lector.leerDirectorio(RUTA);
    vector<string> datosDeLasCampanias;
    vector<string> rutasXML;

    for (unsigned int i = 0; i < archivos.size(); i++) {
        if (archivos[i] == string("campaigns/img")) continue;
        /* Levanta archivo de campaña en memoria (leer cada archivo de campania).*/
        vector<string> datosCampania = parser.cargarDatos(archivos[i]);
        rutasXML.push_back(archivos[i]);
        for (unsigned int j = 0; j < 4; j++) {
            datosDeLasCampanias.push_back(datosCampania[j]);
        }
    }
    /* Pone info de campañas en un string que va a recibir el cliente. */
    string infoCampanias = generarInfoDeCampanias(datosDeLasCampanias);

    // Creo y lanzo hilo de crear partida:
    Server_thread_crear_partida thread_partida;
    thread_partida.setPartidasPendientes(listaDePartidasPendientes);
    thread_partida.setMutexLista(&mutex);
    thread_partida.setFlagCorrer(this->correServer);
    thread_partida.iniciar();

    while (*correServer) {
        Server_socket* nuevo_socket = new Server_socket(PORT);
        lista_sockets.push_back(nuevo_socket);
        if (socket->aceptar_conexion(nuevo_socket) == -1) {
            continue;
        }
        Server_thread_cliente* thread_cliente = new Server_thread_cliente(socket, nuevo_socket);
        lista_threads.push_back(thread_cliente);
        thread_cliente->setFlagCorrer(correServer);
        thread_cliente->setRutasCampanias(rutasXML);
        thread_cliente->setMutexLista(&mutex);
        thread_cliente->setListaPartidas(listaPartidas, listaDePartidasPendientes);
        thread_cliente->setInfoCampanias(infoCampanias);
        thread_cliente->setNumeroCliente(indiceCliente);
        thread_cliente->iniciar(); //lanza hilo de cliente.
        indiceCliente++;
    }
    // join y destroy de hilos.	
    for (unsigned int i = 0; i < lista_threads.size(); i++) {
        lista_threads[i]->join();
        delete lista_threads[i];
    }
    for (unsigned int j = 0; j < lista_sockets.size(); j++) {
        lista_sockets[j]->cerrar_comunicacion();
    }
}

string Server_thread_aceptar::generarInfoDeCampanias(vector<string> info) {
    //extrae los strings, los concatena separados por un '|' y le agrega el largo al principio.
    string buffer;
    string pipe = "|";
    for (unsigned int i = 0; i < info.size(); i++) {
        buffer.append(pipe);
        buffer.append(info[i]);
    }
    int largo = buffer.size() + 1; //??
    char formatted_str[LARGO + 1];
    snprintf(formatted_str, LARGO + 1, "%.5d", largo); //
    string bufferFinal = string(formatted_str);
    bufferFinal.append(buffer);
    return bufferFinal;
}

void Server_thread_aceptar::configurarDatosDePartidas() {
    ParserXML parser;
    // EN LA SIGUIENTE LINEA TIENE Q ESTAR
    string conf = "configuracion.xml";
    vector<string> datosDeConfig = parser.cargarDatos(conf);
    Configuracion::newConfiguracion();
    Configuracion::setAlcanceBomba(stoi(datosDeConfig[0]));
    Configuracion::setDesplazamientoBomberman(stof(datosDeConfig[5]));
    Configuracion::setDesplazamientoDisparo(stof(datosDeConfig[6]));
    Configuracion::setDesplazamientoZombieVerde(stof(datosDeConfig[4]));
    Configuracion::setTamanioMapa(stoi(datosDeConfig[7]));
    Configuracion::setTiempoDetonacionBomba(stoi(datosDeConfig[1]));
    Configuracion::setTiempoRefrescoJuego(stof(datosDeConfig[2]));
    Configuracion::setTiempoRegeneracionBomba(stoi(datosDeConfig[3]));
}
